package com.sky.service.impl;

import com.sky.exception.BaseException;
import com.sky.mapper.OrderMapper;
import com.sky.mapper.ReportMapper;
import com.sky.mapper.UserMapper;
import com.sky.service.ReportService;
import com.sky.service.WorkspaceService;
import com.sky.vo.*;
import lombok.extern.slf4j.Slf4j;
import org.apache.poi.xssf.usermodel.XSSFRow;
import org.apache.poi.xssf.usermodel.XSSFSheet;
import org.apache.poi.xssf.usermodel.XSSFWorkbook;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import javax.servlet.ServletOutputStream;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.io.InputStream;
import java.math.BigDecimal;
import java.math.RoundingMode;
import java.time.LocalDate;
import java.time.LocalTime;
import java.util.*;


@Slf4j
@Service
public class ReportServiceImpl implements ReportService {

    @Autowired
    private ReportMapper reportMapper;
    @Autowired
    private UserMapper userMapper;
    @Autowired
    private OrderMapper orderMapper;
    @Autowired
    private WorkspaceService workspaceService;


    /**
     * Util工具类
     */
    public static List<LocalDate> getDateList(LocalDate begin, LocalDate end) {
        List<LocalDate> dateList = new ArrayList<>();
        dateList.add(begin);
        while(!begin.equals(end)){
            begin = begin.plusDays(1);
            dateList.add(begin);
        }
        return dateList;
    }

    /**
     * 营业额数据统计
     * @param begin
     * @param end
     * @return
     */
    @Override
    public TurnoverReportVO getTurnoverReport(LocalDate begin, LocalDate end) {
        log.info("营业额数据统计:{},{}",begin,end);
        TurnoverReportVO turnoverReportVO = new TurnoverReportVO();
        //封装日期
        List<LocalDate> dateList = getDateList(begin, end);
        turnoverReportVO.setDateList(dateList.toString().substring(1, dateList.toString().length() - 1));
        //调用Mapper层进行查询操作!!!
        DateVO build = DateVO.builder()
                .begin(dateList.get(0).atTime(LocalTime.MIN))
                .end(end.atTime(LocalTime.MAX))
                .build();
        List<CountVO> turnoverReport = reportMapper.getTurnoverReport(build);
        Map<String,BigDecimal> map = new HashMap<>();
        turnoverReport.forEach((item->{
            map.put(item.getDate(),item.getPrice());
        }));
        List<BigDecimal> list = new ArrayList<>();
        dateList.forEach(date->{
            list.add(map.get(date.toString())==null?BigDecimal.ZERO:map.get(date.toString()));
        });
        turnoverReportVO.setTurnoverList(list.toString().substring(1, list.toString().length() - 1));
        log.info("营业额数据统计:{}",turnoverReportVO.getTurnoverList());
        return turnoverReportVO;
    }
    /**
     * 用户统计接口
     * @param begin
     * @param end
     * @return
     */
    @Override
    public UserReportVO getUserReport(LocalDate begin, LocalDate end) {
        log.info("用户统计接口:{},{}",begin,end);
        UserReportVO userReportVO = new UserReportVO();
        //封装日期
        List<LocalDate> dateList = getDateList(begin, end);
        userReportVO.setDateList(dateList.toString().substring(1, dateList.toString().length() - 1));
        //先统计用户的总量!!!!
        List<DateVO> dateVoList = new ArrayList<>();
        //添加结束时间用来指定MySql的createTime的区间
        dateList.forEach(date -> {
            dateVoList.add(DateVO.builder()
                    .begin(date.atTime(LocalTime.MIN))
                    .end(date.atTime(LocalTime.MAX))
                    .build());
        });
        List<Integer> totalUserList = new ArrayList<>();
        List<Integer> newUserList = new ArrayList<>();
        dateVoList.forEach(dateVO -> {
            Integer i = userMapper.countUser(dateVO);
            Integer j = userMapper.countNewUser(dateVO);
            totalUserList.add(i);
            newUserList.add(j);
        });
        userReportVO.setTotalUserList(totalUserList.toString().substring(1, totalUserList.toString().length() - 1));
        userReportVO.setNewUserList(newUserList.toString().substring(1, newUserList.toString().length() - 1));
        log.info("返回统计结果{}",userReportVO.getTotalUserList());
        return userReportVO;
    }

    /**
     * 订单统计接口
     * @param begin
     * @param end
     * @return
     */
    @Override
    public OrderReportVO getOrderReport(LocalDate begin, LocalDate end) {
        log.info("订单统计接口:{},{}", begin, end);
        OrderReportVO orderReportVO = new OrderReportVO();
        //封装日期
        List<LocalDate> dateList = getDateList(begin, end);
        orderReportVO.setDateList(dateList.toString().substring(1, dateList.toString().length() - 1));
        //开始制造数据
        List<Integer> orderCountList = new ArrayList<>();//订单数列表
        List<Integer> validOrderCountList = new ArrayList<>();//有效订单列表
        DateVO build = DateVO.builder()
                .begin(begin.atTime(LocalTime.MIN))
                .end(end.atTime(LocalTime.MAX))
                .build();
        Integer totalOrderCount = orderMapper.getTurnoverReportList(build);//订单总数
        Integer validOrderCount = orderMapper.validOrderCount(build);//有效订单数

        List<DateVO> dateVoList = new ArrayList<>();
        dateList.forEach(date -> {
            dateVoList.add(DateVO.builder()
                    .begin(date.atTime(LocalTime.MIN))
                    .end(date.atTime(LocalTime.MAX))
                    .build());
        });
        dateVoList.forEach(dateVO -> {
            orderCountList.add(orderMapper.getTurnoverReportList(dateVO));
            validOrderCountList.add(orderMapper.validOrderCountList(dateVO));
        });
        orderReportVO.setOrderCountList(orderCountList.toString().substring(1, orderCountList.toString().length() - 1));
        orderReportVO.setValidOrderCountList(validOrderCountList.toString().substring(1, validOrderCountList.toString().length() - 1));
        orderReportVO.setTotalOrderCount(totalOrderCount);
        orderReportVO.setValidOrderCount(validOrderCount);
        //订单完成率
        orderReportVO.setOrderCompletionRate(validOrderCount==0?0:validOrderCount.doubleValue()/totalOrderCount);
        log.info("订单统计结果:{}",orderReportVO);
        return orderReportVO;
    }

    /**
     * 销量排名前10
     * @param begin
     * @param end
     * @return
     */
    @Override
    public SalesTop10ReportVO getSalesTop10(LocalDate begin, LocalDate end) {
        log.info("销量排名前10:{},{}",begin,end);
        List<TopVO> salesTop10 = orderMapper.getSalesTop10(DateVO.builder()
                .begin(begin.atTime(LocalTime.MIN))
                .end(end.atTime(LocalTime.MAX))
                .build());
        SalesTop10ReportVO salesTop10ReportVO = new SalesTop10ReportVO();
        List<String> nameList = new ArrayList<>();
        List<Integer> numberList = new ArrayList<>();
        salesTop10.forEach(topVO -> {
            nameList.add(String.valueOf(topVO.getName()));
            numberList.add(topVO.getNum());
        });
        salesTop10ReportVO.setNameList(nameList.toString().substring(1, nameList.toString().length() - 1));
        salesTop10ReportVO.setNumberList(numberList.toString().substring(1, numberList.toString().length() - 1));
        return salesTop10ReportVO;
    }
    /**
     * 导出Excel报表接口
     */
    @Override
    public void exportExcel(HttpServletResponse response) throws IOException {
        //先获取时间区间值
        List<LocalDate> dateList = new ArrayList();
        LocalDate end = LocalDate.now();
        //获取时间区间的开始时间
        LocalDate begin = end.minusDays(30);
        while (!end.equals(begin)) {
            dateList.add(begin);
            begin = begin.plusDays(1);
        }
        //查询近30天的营业额!!
        //TODO 这里的优化没有做好 还有之前的mybatis 数据库查询 这里给数据库太大压力了 但是我是一个人用后台管理系统所以我就没有优化了
        //Table Data
        List<BusinessDataVO> businessDataVOList = new ArrayList<>();
        dateList.forEach(date -> {
            BusinessDataVO businessData = workspaceService.getBusinessData(date.atTime(LocalTime.MIN), date.atTime(LocalTime.MAX));
            businessDataVOList.add(businessData);
        });
        //这里要计算表头的数据!!
        BigDecimal turnover = new BigDecimal(0);//营业额
        Integer validOrderCount = 0;//有效订单数
        BigDecimal orderCompletionRate = new BigDecimal(0);//订单完成率
        BigDecimal unitPrice =  new BigDecimal(0);//平均客单价
        Integer newUsers = 0;//新增用户数
        for (BusinessDataVO businessDataVO : businessDataVOList) {
            turnover = turnover.add(businessDataVO.getTurnover());
            validOrderCount = validOrderCount + businessDataVO.getValidOrderCount();
            orderCompletionRate = orderCompletionRate.add(businessDataVO.getOrderCompletionRate().multiply(new BigDecimal(100)));
            unitPrice = unitPrice.add(businessDataVO.getUnitPrice());
            newUsers = newUsers + businessDataVO.getNewUsers();
        }
        //计算订单完成率!!
        orderCompletionRate = orderCompletionRate.divide(new BigDecimal(businessDataVOList.size()), 2, RoundingMode.HALF_UP);
        unitPrice = unitPrice.divide(new BigDecimal(businessDataVOList.size()), 2, RoundingMode.HALF_UP);
        //塞入数据
        InputStream inputStream = this.getClass().getClassLoader().getResourceAsStream("template/运营数据报表模板.xlsx");
        try {
            XSSFWorkbook excel = new XSSFWorkbook(inputStream);//读取表格模版数据
            log.info("导出Excel报表接口:{}",businessDataVOList);
            //开始写入(表头)数据
            XSSFSheet sheet = excel.getSheetAt(0);//获取到第一个sheet
            sheet.getRow(1).getCell(1).setCellValue(dateList.get(0).toString() + "  至  " + dateList.get(dateList.size() - 1).toString());
            XSSFRow row3 = sheet.getRow(3);//获取到第二行
            row3.getCell(2).setCellValue(turnover +" /CNY");
            row3.getCell(4).setCellValue(orderCompletionRate +"%");
            row3.getCell(6).setCellValue(newUsers +" /人");
            XSSFRow row4 = sheet.getRow(4);//获取到第二行
            row4.getCell(2).setCellValue(validOrderCount.toString());
            row4.getCell(4).setCellValue(unitPrice +" /CNY");
            int rowIndex = 7, listIndex=0;
            //写入Table Body Data
            for (BusinessDataVO businessDataVO : businessDataVOList) {
                XSSFRow row = sheet.getRow(rowIndex);
                row.getCell(1).setCellValue(dateList.get(listIndex).toString());
                row.getCell(2).setCellValue(businessDataVO.getTurnover()+" /CNY");
                row.getCell(3).setCellValue(businessDataVO.getValidOrderCount().toString());
                row.getCell(4).setCellValue(businessDataVO.getOrderCompletionRate().multiply(new BigDecimal(100))+"%");
                row.getCell(5).setCellValue(businessDataVO.getUnitPrice()+" /CNY");
                row.getCell(6).setCellValue(businessDataVO.getNewUsers().toString()+"/人");
                rowIndex++;
                listIndex++;
            }
            ServletOutputStream outputStream = response.getOutputStream();
            excel.write(outputStream);
            outputStream.close();
            excel.close();
        }catch (Exception e){
            throw new BaseException("导出Excel报表接口失败");
        }
    }
}